package wen_du

import (
	"device-modbus/core"
	"device-modbus/internal/biz/model"
	"encoding/binary"
	"fmt"
	"time"

	"github.com/cloudwego/hertz/pkg/common/hlog"
)

// WenDuSensorProtocol 温湿度传感器协议实现（必须实现 core.SensorProtocol 接口）
type WenDuSensorProtocol struct{}

var _ core.ProtocolCreator = NewProtocol // 编译时检查：若不匹配会直接报错

// NewProtocol 导出插件创建函数
func NewProtocol() core.SensorProtocol {
	return &WenDuSensorProtocol{}
}

// GetType 返回传感器类型
func (p *WenDuSensorProtocol) GetType() string {
	return "modbus"
}

// GetModel 返回传感器型号
func (p *WenDuSensorProtocol) GetModel() string {
	return "百叶窗传感器"
}

// GetProtocolName 返回协议唯一标识
func (p *WenDuSensorProtocol) GetProtocolName() string {
	return "百叶窗"
}

// WenDuSensorData 温湿度传感器解析后的数据结构
type WenDuSensorData struct {
	DeviceAddr  byte    // 设备地址
	FuncCode    byte    // 功能码
	ValidBytes  byte    // 有效字节数
	Humidity    float64 // 湿度（%RH，实际值 ÷ 10）
	Temperature float64 // 温度（℃，实际值 ÷ 10）
	Noise       float64 // 噪声（dB，实际值 ÷ 10）
	CO2         float64 // CO₂浓度
	Pressure    float64 // 大气压（kPa，实际值 ÷ 10）
	Light       uint32  // 光照（Lux，高16位+低16位合成）
}

// BuildRequest 构建Modbus请求帧
func (p *WenDuSensorProtocol) BuildRequest(deviceAddr, funcCode byte, startAddr, dataLength uint16) ([]byte, error) {
	hlog.Debugf("构建请求 | 设备地址: 0x%02X, 功能码: 0x%02X, 起始地址: 0x%04X, 长度: 0x%04X",
		deviceAddr, funcCode, startAddr, dataLength)

	// 构建帧主体（地址+功能码+起始地址+数据长度）
	frame := make([]byte, 6)
	frame[0] = deviceAddr
	frame[1] = funcCode
	binary.BigEndian.PutUint16(frame[2:4], startAddr)
	binary.BigEndian.PutUint16(frame[4:6], dataLength)

	// 计算并添加CRC校验
	crc := calculateCRC(frame)
	frame = append(frame, byte(crc&0xFF))    // CRC低字节
	frame = append(frame, byte(crc>>8&0xFF)) // CRC高字节

	return frame, nil
}

// ParseResponse 解析传感器响应帧
func (p *WenDuSensorProtocol) ParseResponse(resp []byte) (*model.SensorData, error) {
	// 1. 校验帧长度
	// 1. 校验帧长度（地址1 + 功能码1 + 有效字节数1 + 数据16 + CRC2 = 21字节）
	const expectedLen = 21
	if len(resp) != expectedLen {
		return nil, fmt.Errorf("%w: 帧长度应为%d，实际%d", core.ErrorInvalidResponse, expectedLen, len(resp))
	}

	// 2. 校验设备地址、功能码、有效字节数
	if resp[0] != 0x02 {
		return nil, fmt.Errorf("%w: 设备地址应为0x02，实际0x%02X", core.ErrorInvalidResponse, resp[0])
	}
	// 功能码（仅支持0x03读寄存器）
	if resp[1] != 0x03 {
		return nil, fmt.Errorf("%w: 功能码应为0x03，实际0x%02X", core.ErrorInvalidResponse, resp[1])
	}
	// 有效字节数（读取8个寄存器，每个2字节 → 共16字节，即0x10）
	if resp[2] != 0x10 {
		return nil, fmt.Errorf("%w: 有效字节数应为0x10，实际0x%02X", core.ErrorInvalidResponse, resp[2])
	}

	// 3. CRC校验（校验前19字节）
	crcData := resp[:19]
	expectedCRC := calculateCRC(crcData)
	actualCRC := uint16(resp[19]) | uint16(resp[20])<<8
	if actualCRC != expectedCRC {
		return nil, fmt.Errorf("%w: CRC校验失败（预期0x%04X，实际0x%04X）", core.ErrorInvalidResponse, expectedCRC, actualCRC)
	}

	// 4. 解析数据区（resp[3:19]为16字节数据，对应8个寄存器）
	dataArea := resp[3:19]

	// 解析各寄存器（按手册寄存器地址顺序）：
	// 寄存器500 → 湿度（实际值 × 10 → 需 ÷ 10）
	humidityRaw := binary.BigEndian.Uint16(dataArea[0:2])
	humidity := float64(humidityRaw) / 10.0

	// 寄存器501 → 温度（实际值 × 10 → 需 ÷ 10）
	tempRaw := binary.BigEndian.Uint16(dataArea[2:4])
	temperature := float64(tempRaw) / 10.0

	// 寄存器502 → 噪声（实际值 × 10 → 需 ÷ 10）
	noiseRaw := binary.BigEndian.Uint16(dataArea[4:6])
	noise := float64(noiseRaw) / 10.0

	// 寄存器503 → CO₂浓度（直接取实际值）
	co2 := float64(binary.BigEndian.Uint16(dataArea[6:8]))

	// 寄存器505 → 大气压（单位kPa，实际值 × 10 → 需 ÷ 10）
	pressureRaw := binary.BigEndian.Uint16(dataArea[10:12])
	pressure := float64(pressureRaw) / 10.0

	// 寄存器506（高16位） + 507（低16位） → 光照（合成32位）
	lightHi := binary.BigEndian.Uint16(dataArea[12:14])
	lightLo := binary.BigEndian.Uint16(dataArea[14:16])
	light := uint32(lightHi)<<16 | uint32(lightLo)

	// 5. 封装解析结果
	parsed := &WenDuSensorData{
		DeviceAddr:  resp[0],
		FuncCode:    resp[1],
		ValidBytes:  resp[2],
		Humidity:    humidity,
		Temperature: temperature,
		Noise:       noise,
		CO2:         co2,
		Pressure:    pressure,
		Light:       light,
	}

	hlog.Debugf("解析成功 | 湿度=%.1f%%, 温度=%.1f℃, 噪声=%.1fdB, "+
		"CO₂=%.1f ppm, 气压=%.1fkPa, 光照=%dLux",
		parsed.Humidity, parsed.Temperature, parsed.Noise,
		parsed.CO2, parsed.Pressure, parsed.Light)

	// 6. 转换为全局统一的 SensorData 结构
	return &model.SensorData{
		SensorID:  fmt.Sprintf("%d-%s", parsed.DeviceAddr, p.GetType()),
		Type:      p.GetType(),
		Model:     p.GetModel(),
		Timestamp: time.Now().UnixMilli(),
		RawData:   resp,
		Protocol:  p.GetProtocolName(),
		Values: map[string]string{
			"humidity":    fmt.Sprintf("%.1f", parsed.Humidity),
			"temperature": fmt.Sprintf("%.1f", parsed.Temperature),
			"noise":       fmt.Sprintf("%.1f", parsed.Noise),
			"co2":         fmt.Sprintf("%.1f", parsed.CO2),
			"pressure":    fmt.Sprintf("%.1f", parsed.Pressure),
			"light":       fmt.Sprintf("%d", parsed.Light),
		},
	}, nil
}

func calculateCRC(data []byte) uint16 {
	crc := uint16(0xFFFF)
	for _, b := range data {
		crc ^= uint16(b)
		for i := 0; i < 8; i++ {
			if crc&0x0001 != 0 {
				crc >>= 1
				crc ^= 0xA001 // 多项式
			} else {
				crc >>= 1
			}
		}
	}
	return crc
}
